package com.wetao.lib_common.view.graffiti;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.PaintFlagsDrawFilter;
import android.graphics.RectF;
import android.os.Looper;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.widget.FrameLayout;

import com.wetao.lib_common.utils.ComUtil;
import com.wetao.lib_common.utils.LogUtils;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import io.reactivex.Observable;
import io.reactivex.ObservableEmitter;
import io.reactivex.ObservableOnSubscribe;
import io.reactivex.Observer;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.disposables.Disposable;
import io.reactivex.schedulers.Schedulers;

public class GraffitiView  extends FrameLayout {


    private static final int FLAG_RESET_BACKGROUND = 1 << 1;
    private static final int FLAG_DRAW_PENDINGS_TO_BACKGROUND = 1 << 2;
    private static final int FLAG_REFRESH_BACKGROUND = 1 << 3;

    private Context mContext;
    private Bitmap mBitmap_b;
    private Bitmap mBitmap_f;
    private Bitmap mBitmap_c;
    private ForegroundView mForegroundView;
    private BackgroundView mBackgroundView;

    private MaskView mMaskView_b;
    private MaskView mMaskView_r;
    private Paint mMaskPaint;

    private boolean mIsHaveMask;
    private boolean mIsDrawableOutside = false; // 触摸时，图片区域外是否绘制涂鸦轨迹
    private boolean mIsNoTouch = false; //是否有触摸
    private boolean isJustDrawOriginal; // 是否只绘制原图
    /**
     * Whether or not to optimize drawing, it is suggested to open, which can optimize the drawing speed and performance.
     * Note: When item is selected for editing after opening, it will be drawn at the top level, and not at the corresponding level until editing is completed.
     * 是否优化绘制，建议开启，可优化绘制速度和性能.
     * 注意：开启后item被选中编辑时时会绘制在最上面一层，直到结束编辑后才绘制在相应层级
     **/
    private boolean mOptimizeDrawing; // 涂鸦及时绘制在图片上，优化性能

    private Paint mPenPaint;
    private float mPenSize = 1;

    private float mTouchX, mTouchY;
    private Matrix mTouchEventMatrix = new Matrix();

    private int mFlags = 0;
    private float mScale = 1; // 在适应屏幕时的缩放基础上的缩放倍数 （ 图片真实的缩放倍数为 mCenterScale*mScale ）
    private float mTransX = 0, mTransY = 0; // 图片在适应屏幕且处于居中位置的基础上的偏移量（ 图片真实偏移量为mCentreTranX + mTransX，View窗口坐标系上的偏移）

    private boolean mIsSaving = false;

    private Canvas mGraffitiBitmapCanvas;

    private List<GraffitiPath> mItemStackOnViewCanvas = new ArrayList<>(); // 这些item绘制在View的画布上，而不是在图片Bitmap.比如正在创建或选中的item
    private List<GraffitiPath> mPendingItemsDrawToBitmap = new ArrayList<>();

    // 保存涂鸦操作，便于撤销
    private List<GraffitiPath> mItemStack = new ArrayList<>();
    private List<GraffitiPath> mRedoItemStack = new ArrayList<>();

    // 手势相关
    private IGraffitiTouchDetector mDefaultTouchDetector;

    private boolean mIsInit =false;

    private IGraffitiViewListener mListener;
    public interface IGraffitiViewListener{
        void onSaved(List<Bitmap> bitmaps);
    }

    /**
     * @param bitmap_b 底图图片;
     * @param bitmap_f 上层图片，可以为空
     * @param isHaveMask 是否需要白色遮挡，比如一页纸只显示中间部分，可以移动图片，然后将下部分和有部分遮挡住
     * @param isOptimizeDrawing 是否优化绘图
     * */
    public GraffitiView(Context context, Bitmap bitmap_b, Bitmap bitmap_f, boolean isHaveMask, boolean isOptimizeDrawing, IGraffitiViewListener listener) {
        super(context);
        LogUtils.i("m3: 构造函数");

        setClipChildren(false);

        mPenPaint = new Paint();
        mPenPaint.setColor(Color.BLACK);
        mPenPaint.setStyle(Paint.Style.STROKE);
        mPenPaint.setAntiAlias(true);
        mPenPaint.setStrokeJoin(Paint.Join.ROUND);
        mPenPaint.setStrokeCap(Paint.Cap.ROUND);// 圆滑
        mPenPaint.setStrokeWidth(1);


        mContext = context;
        mBitmap_b = bitmap_b;
        mBitmap_f = bitmap_f;
        mIsHaveMask = isHaveMask;
        mListener = listener;
        mOptimizeDrawing = isOptimizeDrawing;
        if(mOptimizeDrawing) {
            if(mBitmap_f == null) {
                mBitmap_c = mBitmap_b.copy(mBitmap_b.getConfig(), true);
            } else {
                mBitmap_c = ComUtil.combineBitmap(mBitmap_b, mBitmap_f);
            }
        }


        LogUtils.i("m3: mBitmap_b: width:" + mBitmap_b.getWidth() + ", height:" + mBitmap_b.getHeight());
        if(mBitmap_f != null) {
            LogUtils.i("m3: mBitmap_f: width:" + mBitmap_f.getWidth() + ", height:" + mBitmap_f.getHeight());
        }

        if (mBitmap_b == null) {
            throw new RuntimeException("Bitmap is null!!!");
        }


        mMaskPaint = new Paint();
        mMaskPaint.setColor(Color.parseColor("#ffffff"));
        mMaskPaint.setStyle(Paint.Style.FILL);
        mMaskPaint.setAntiAlias(true);

        mForegroundView = new ForegroundView(context);
        mBackgroundView = new BackgroundView(context);

        addView(mBackgroundView, new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
        addView(mForegroundView, new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));


        if(mIsHaveMask) {
            mMaskView_b = new MaskView(context);
            mMaskView_r = new MaskView(context);
            addView(mMaskView_b, new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
            addView(mMaskView_r, new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
        }
    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        LogUtils.i("m3: onSizeChanged w:" + w + ", h:" + h + ", oldw:" + oldw + ", oldh:" + oldh);
        if(!mIsInit) {
            mIsInit = true;
            init();
        }
    }

    @Override
    public boolean dispatchTouchEvent(MotionEvent event) {
        LogUtils.i("m3: dispatchTouchEvent x:" + event.getX() + ", y:" + event.getY());
        if (mIsNoTouch) {
            return true;
        }

        mTouchX = event.getX();
        mTouchY = event.getY();

        // 把事件转发给innerView，避免在区域外不可点击
        MotionEvent transformedEvent = MotionEvent.obtain(event);
//        final float offsetX = mForegroundView.getScrollX() - mForegroundView.getLeft();
//        final float offsetY = mForegroundView.getScrollY() - mForegroundView.getTop();
//        transformedEvent.offsetLocation(offsetX, offsetY);
        mTouchEventMatrix.reset();
        mTouchEventMatrix.setRotate(-0, getWidth() / 2, getHeight() / 2);
        transformedEvent.transform(mTouchEventMatrix);
        boolean handled = mForegroundView.onTouchEvent(transformedEvent);
        transformedEvent.recycle();

        return handled;
    }

    @Override
    public void setOnTouchListener(OnTouchListener l) {
        super.setOnTouchListener(l);
        LogUtils.i("m3: setOnTouchListener");
    }

    @Override
    protected void dispatchDraw(Canvas canvas) {
        LogUtils.i("m3: dispatchDraw");
        canvas.setDrawFilter(new PaintFlagsDrawFilter(0, Paint.ANTI_ALIAS_FLAG | Paint.FILTER_BITMAP_FLAG));
        int count = canvas.save();
        super.dispatchDraw(canvas);
        if (hasFlag(FLAG_RESET_BACKGROUND)) {
            //LogUtil.d(TAG, "FLAG_RESET_BACKGROUND");
            clearFlag(FLAG_RESET_BACKGROUND);
            clearFlag(FLAG_DRAW_PENDINGS_TO_BACKGROUND);
            clearFlag(FLAG_REFRESH_BACKGROUND);
            refreshGraffitiBitmap(false);
            mPendingItemsDrawToBitmap.clear();
            mBackgroundView.invalidate();
        } else if (hasFlag(FLAG_DRAW_PENDINGS_TO_BACKGROUND)) {
            //LogUtil.d(TAG, "FLAG_DRAW_PENDINGS_TO_BACKGROUND");
            clearFlag(FLAG_DRAW_PENDINGS_TO_BACKGROUND);
            clearFlag(FLAG_REFRESH_BACKGROUND);
            drawToGraffitiBitmap(mPendingItemsDrawToBitmap);
            mPendingItemsDrawToBitmap.clear();
            mBackgroundView.invalidate();
        } else if (hasFlag(FLAG_REFRESH_BACKGROUND)) {
            //LogUtil.d(TAG, "FLAG_REFRESH_BACKGROUND");
            clearFlag(FLAG_REFRESH_BACKGROUND);
            mBackgroundView.invalidate();
        }

        canvas.restoreToCount(count);

        /*// test
        mPaint.setStyle(Paint.Style.STROKE);
        mPaint.setColor(Color.BLUE);
        mPaint.setStrokeWidth(20);
        canvas.drawRect(getDoodleBound(), mPaint);*/

    }

    @Override
    public void invalidate() {
        LogUtils.i("m3: invalidate");
        refresh();
    }



    private void init() {
        LogUtils.i("m3: init");

        // 居中适应屏幕
        mTransX = mTransY = 0;
        mScale = 1;

        initGraffitiBitmap();

        refreshWithBackground();
    }

    private void initGraffitiBitmap() {
        LogUtils.i("m3: initGraffitiBitmap");
        if (!mOptimizeDrawing) {
            return;
        }

        mGraffitiBitmapCanvas = new Canvas(mBitmap_c);
        mGraffitiBitmapCanvas.setDrawFilter(new PaintFlagsDrawFilter(0, Paint.ANTI_ALIAS_FLAG | Paint.FILTER_BITMAP_FLAG));
    }

    public Paint getmPenPaint() {
        return mPenPaint;
    }

    private boolean hasFlag(int flag) {
        return (mFlags & flag) != 0;
    }

    private void addFlag(int flag) {
        mFlags = mFlags | flag;
    }

    private void clearFlag(int flag) {
        mFlags = mFlags & ~flag;
    }

    public float getAllScale() {
        return  mScale;
    }

    public float getAllTranX() {
        return mTransX;
    }

    public float getAllTranY() {
        return mTransY;
    }

    /**
     * 设置默认手势识别器
     *
     * @param touchGestureDetector
     */
    public void setDefaultTouchDetector(IGraffitiTouchDetector touchGestureDetector) {
        mDefaultTouchDetector = touchGestureDetector;
    }

    public void setNoTouch(boolean isNoTouch) {
        mIsNoTouch = isNoTouch;
    }

    /**
     * 设置画笔底色
     *
     * @param color
     */
    public void setColor(int color) {
        mPenPaint.setColor(color);
        refresh();
    }

    public void setSize(float paintSize) {
        mPenSize = paintSize;
        mPenPaint.setStrokeWidth(paintSize);
        refresh();
    }
    public float getSize() {
        return mPenSize;
    }

    /**
     * 触摸时，图片区域外是否绘制涂鸦轨迹
     *
     * @param isDrawableOutside
     */
    public void setIsDrawableOutside(boolean isDrawableOutside) {
        mIsDrawableOutside = isDrawableOutside;
    }

    public boolean isOptimizeDrawing() {
        return mOptimizeDrawing;
    }
    /*public void setmOptimizeDrawing(boolean isOptimizeDrawing) {
        mOptimizeDrawing = isOptimizeDrawing;
    }*/

    public void setGraffitiTranslation(float transX, float transY) {
        LogUtils.i("m3: setGraffitiTranslation transX:" + transX + ", transY:" + transY);
        mTransX = transX;
        mTransY = transY;
        refreshWithBackground();
    }

    /**
     * 设置图片G偏移
     *
     * @param transX
     */
    public void setGraffitiTranslationX(float transX) {
        LogUtils.i("m3: setGraffitiTranslationX transX:" + transX);
        this.mTransX = transX;
        refreshWithBackground();
    }

    public float getGraffitiTranslationX() {
        return mTransX;
    }

    public void setGraffitiTranslationY(float transY) {
        LogUtils.i("m3: setGraffitiTranslationY transY:" + transY);
        this.mTransY = transY;
        refreshWithBackground();
    }

    public float getGraffitiTranslationY() {
        return mTransY;
    }

    public int getBitmapWidth() {
        if(mBitmap_b != null && mBitmap_f != null) {
            return mBitmap_b.getWidth() > mBitmap_f.getWidth() ? mBitmap_b.getWidth() : mBitmap_f.getWidth();
        }
        return mBitmap_b.getWidth();
    }

    public int getBitmapHeight() {
        if(mBitmap_b != null && mBitmap_f != null) {
            return mBitmap_b.getHeight() > mBitmap_f.getHeight() ? mBitmap_b.getHeight() : mBitmap_f.getHeight();
        }
        return mBitmap_b.getHeight();
    }

    public void setShowOriginal(boolean justDrawOriginal) {
        isJustDrawOriginal = justDrawOriginal;
        refreshWithBackground();
    }

    public boolean isShowOriginal() {
        return isJustDrawOriginal;
    }


    public int getItemCount() {
        return mItemStack == null ? 0 : mItemStack.size();
    }

    public List<GraffitiPath> getAllItem() {
        return new ArrayList<>(mItemStack);
    }



    /**
     * 将屏幕触摸坐标x转换成在图片中的坐标
     */
    public final float toX(float touchX) {
        return (touchX - getAllTranX()) / getAllScale();
    }

    /**
     * 将屏幕触摸坐标y转换成在图片中的坐标
     */
    public final float toY(float touchY) {
        return (touchY - getAllTranY()) / getAllScale();
    }

    /**
     * 将图片坐标x转换成屏幕触摸坐标
     */
    public final float toTouchX(float x) {
        return x * getAllScale() + getAllTranX();
    }

    /**
     * 将图片坐标y转换成屏幕触摸坐标
     */
    public final float toTouchY(float y) {
        return y * getAllScale() + getAllTranY();
    }

    /**
     * 坐标换算
     * （公式由toX()中的公式推算出）
     *
     * @param touchX  触摸坐标
     * @param graffitiX 在涂鸦图片中的坐标
     * @return 偏移量
     */
    public final float toTransX(float touchX, float graffitiX) {
        return -graffitiX * getAllScale() + touchX;
    }

    public final float toTransY(float touchY, float graffitiY) {
        return -graffitiY * getAllScale() + touchY;
    }


    public void refreshMaskView(float gridW, float gridH, int bigW, int bigH) {
        LogUtils.i("refreshMaskView--- gridW:" + gridW + ", gridH:" + gridH + ", bigW:" + bigW + ", bigH:" + bigH);
        mMaskView_b.setRect(0, gridH, bigW, bigH);
        mMaskView_r.setRect(gridW, 0, bigW, bigH);
    }


    private void refreshWithBackground() {
        LogUtils.i("m3: refreshWithBackground");
        addFlag(FLAG_REFRESH_BACKGROUND);
        refresh();
    }

    public void refresh() {
        LogUtils.i("m3: refresh");
        if (Looper.myLooper() == Looper.getMainLooper()) {
            super.invalidate();
            mForegroundView.invalidate();
        } else {
            super.postInvalidate();
            mForegroundView.postInvalidate();
        }
    }


    public void clear() {
        List<GraffitiPath> temp = new ArrayList<>(mItemStack);
        mItemStack.clear();
        mRedoItemStack.clear();
        mItemStackOnViewCanvas.clear();
        mPendingItemsDrawToBitmap.clear();

        for (int i = temp.size() - 1; i >= 0; i--) {
            GraffitiPath item = temp.get(i);
            item.onRemove();
        }

        addFlag(FLAG_RESET_BACKGROUND);

        refresh();
    }

    private void addItemInner(GraffitiPath item) {
        LogUtils.i("m3: addItemInner");
        if (item == null) {
            throw new RuntimeException("item is null");
        }

        if (this != item.getDoodle()) {
            throw new RuntimeException("the object Doodle is illegal");
        }
        if (mItemStack.contains(item)) {
            throw new RuntimeException("the item has been added");
        }

        mItemStack.add(item);
        item.onAdd();

        mPendingItemsDrawToBitmap.add(item);
        addFlag(FLAG_DRAW_PENDINGS_TO_BACKGROUND);

        refresh();
    }

    public void removeItem(GraffitiPath graffitiItem) {
        LogUtils.i("m3: removeItem");
        if (!mItemStack.remove(graffitiItem)) {
            return;
        }

        mItemStackOnViewCanvas.remove(graffitiItem);
        mPendingItemsDrawToBitmap.remove(graffitiItem);
        graffitiItem.onRemove();

        addFlag(FLAG_RESET_BACKGROUND);

        refresh();
    }

    private void drawToGraffitiBitmap(List<GraffitiPath> items) {
        LogUtils.i("m3: drawToGraffitiBitmap");
        if (!mOptimizeDrawing) {
            return;
        }

        Iterator<GraffitiPath> it_b = items.iterator();
        while (it_b.hasNext()) {
            GraffitiPath item = it_b.next();
            item.draw(mGraffitiBitmapCanvas);
        }

        /*for (GraffitiPath item : items) {
            item.draw(mGraffitiBitmapCanvas);
        }*/
    }

    private void refreshGraffitiBitmap(boolean drawAll) {
        LogUtils.i("m3: refreshGraffitiBitmap");
        if (!mOptimizeDrawing) {
            return;
        }

        initGraffitiBitmap();
        List<GraffitiPath> items = null;
        if (drawAll) {
            items = mItemStack;
        } else {
            items = new ArrayList<>(mItemStack);
            items.removeAll(mItemStackOnViewCanvas);
        }
        for (GraffitiPath item : items) {
            item.draw(mGraffitiBitmapCanvas);
        }
    }

    /**
     * 标志item绘制在View的画布上，而不是在图片Bitmap. 比如正创建或选中的item. 结束绘制时应调用
     * 仅在开启优化绘制（mOptimizeDrawing=true）时生效
     *
     * @param item
     */
    public void markItemToOptimizeDrawing(GraffitiPath item) {
        LogUtils.i("m3: markItemToOptimizeDrawing");
        if (!mOptimizeDrawing) {
            return;
        }

        if (mItemStackOnViewCanvas.contains(item)) {
            throw new RuntimeException("The item has been added");
        }

        mItemStackOnViewCanvas.add(item);

        if (mItemStack.contains(item)) {
            addFlag(FLAG_RESET_BACKGROUND);
        }

        refresh();
    }

    public void addItem(GraffitiPath item) {
        LogUtils.i("m3: addItem");
        addItemInner(item);
        mRedoItemStack.clear();
    }

    /**
     * 把item从View画布中移除并绘制在涂鸦图片上. 对应
     *
     * @param item
     */
    public void notifyItemFinishedDrawing(GraffitiPath item) {
        LogUtils.i("m3: notifyItemFinishedDrawing");
        if (!mOptimizeDrawing) {
            return;
        }

        if (mItemStackOnViewCanvas.remove(item)) {
            if (mItemStack.contains(item)) {
                addFlag(FLAG_RESET_BACKGROUND);
            } else {
                addItem(item);
            }
        }

        refresh();
    }

    /**
     * 该方式原理主要是：View组件显示的内容可以通过cache机制保存为bitmap
     */
    public static Bitmap createBitmapFromView(View view) {
        Bitmap bitmap = null;
        //开启view缓存bitmap
        view.setDrawingCacheEnabled(true);
        //设置view缓存Bitmap质量
        view.setDrawingCacheQuality(DRAWING_CACHE_QUALITY_HIGH);
        //获取缓存的bitmap
        Bitmap cache = view.getDrawingCache();
        if (cache != null && !cache.isRecycled()) {
            bitmap = Bitmap.createBitmap(cache);
        }
        //销毁view缓存bitmap
        view.destroyDrawingCache();
        //关闭view缓存bitmap
        view.setDrawingCacheEnabled(false);
        return bitmap;
    }


    public void save() {
        if (mIsSaving) {
            return;
        }

        mIsSaving = true;

        Observable.create(new ObservableOnSubscribe<List<Bitmap>>() {
            @Override
            public void subscribe(final ObservableEmitter<List<Bitmap>> emitter) throws Exception {
                LogUtils.i("========================= subscribe currentThread name: " + Thread.currentThread().getName());

                List<Bitmap> savedBitmapList = new ArrayList<>();

                if (mOptimizeDrawing) {
                    refreshGraffitiBitmap(true);
                    savedBitmapList.add(mBitmap_b);
                    if(mBitmap_f != null) {
                        savedBitmapList.add(mBitmap_f);
                    }
                } else {
                    Bitmap savedBitmap_c = mBitmap_b.copy(mBitmap_b.getConfig(), true);
                    Canvas canvas_c = new Canvas(savedBitmap_c);
                    canvas_c.setDrawFilter(new PaintFlagsDrawFilter(0, Paint.ANTI_ALIAS_FLAG | Paint.FILTER_BITMAP_FLAG));
                    for (GraffitiPath item : mItemStack) {
                        item.draw(canvas_c);
                    }
                    //Bitmap savedBitmap_c = createBitmapFromView(GraffitiView.this);
                    savedBitmapList.add(savedBitmap_c);

                    if(mBitmap_f != null) {
                        Bitmap savedBitmap_f = mBitmap_f.copy(mBitmap_f.getConfig(), true);
                        Canvas canvas_f = new Canvas(savedBitmap_f);
                        canvas_f.setDrawFilter(new PaintFlagsDrawFilter(0, Paint.ANTI_ALIAS_FLAG | Paint.FILTER_BITMAP_FLAG));
                        for (GraffitiPath item : mItemStack) {
                            item.draw(canvas_f);
                        }
                        //Bitmap savedBitmap_f = createBitmapFromView(mForegroundView);
                        savedBitmapList.add(savedBitmap_f);
                    }
                }
                emitter.onNext(savedBitmapList);
                emitter.onComplete();

            }
        }).subscribeOn(Schedulers.newThread())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(new Observer<List<Bitmap>>() {
            @Override
            public void onSubscribe(Disposable d) {
                //创建只运行1次，执行顺序1 -- main
                LogUtils.i("========================= onSubscribe currentThread name: " + Thread.currentThread().getName());

            }

            @Override
            public void onNext(List<Bitmap> o) {
                //运行多次 执行顺序3 -- thread
                LogUtils.i("========================= onNext currentThread name: " + Thread.currentThread().getName());
                mIsSaving = false;
                mListener.onSaved(o);
            }

            @Override
            public void onError(Throwable e) {
                //运行1次  -- thread
                LogUtils.i("========================= onError currentThread name: " + Thread.currentThread().getName() + "--" + e.getMessage());

            }

            @Override
            public void onComplete() {
                //运行1次  -- thread
                LogUtils.i("========================= onComplete currentThread name: " + Thread.currentThread().getName());

            }
        });

    }

    // 背景图层，只在背景发生变化时绘制
    private class BackgroundView extends View {

        public BackgroundView(Context context) {
            super(context);
        }

        @Override
        protected void onDraw(Canvas canvas) {
            LogUtils.i("m3: BackgroundView onDraw");
            canvas.setDrawFilter(new PaintFlagsDrawFilter(0, Paint.ANTI_ALIAS_FLAG | Paint.FILTER_BITMAP_FLAG));

            int count = canvas.save();
            doDraw(canvas);
            canvas.restoreToCount(count);
        }

        private void doDraw(Canvas canvas) {
            float left = getAllTranX();
            float top = getAllTranY();

            // 画布和图片共用一个坐标系，只需要处理屏幕坐标系到图片（画布）坐标系的映射关系
            canvas.translate(left, top); // 偏移画布
            float scale = getAllScale();
            canvas.scale(scale, scale); // 缩放画布

            if (isJustDrawOriginal) { // 只绘制原图
                canvas.drawBitmap(mBitmap_b, 0, 0, null);
                return;
            }

            Bitmap bitmap = mOptimizeDrawing ? mBitmap_c : mBitmap_b;
            int w = bitmap.getWidth();
            int h = bitmap.getHeight();

            // 绘制涂鸦后的图片
            canvas.drawBitmap(bitmap, 0, 0, null);
        }

    }

    // 前景图层，每次刷新都会绘制，用于绘制正在创建或选中的item
    private class ForegroundView extends View {
        public ForegroundView(Context context) {
            super(context);

            // 关闭硬件加速，某些绘图操作不支持硬件加速
            //setLayerType(LAYER_TYPE_SOFTWARE, null); //有这句代码，会在rcyclerview中，超过一页的的涂鸦，中途无法绘制，只能在抬笔时绘制
        }

        @Override
        public boolean onTouchEvent(MotionEvent event) {
            // 默认识别器
            if (mDefaultTouchDetector != null) {
                return mDefaultTouchDetector.onTouchEvent(event);
            }
            return false;
        }

        @Override
        protected void onDraw(Canvas canvas) {
            LogUtils.i("m3: ForegroundView onDraw");
            canvas.setDrawFilter(new PaintFlagsDrawFilter(0, Paint.ANTI_ALIAS_FLAG | Paint.FILTER_BITMAP_FLAG));

            int count = canvas.save();
            doDraw(canvas);
            canvas.restoreToCount(count);
        }

        private void doDraw(Canvas canvas) {

            if (isJustDrawOriginal) { // 只绘制原图
                return;
            }

            float left = getAllTranX();
            float top = getAllTranY();

            // 画布和图片共用一个坐标系，只需要处理屏幕坐标系到图片（画布）坐标系的映射关系
            canvas.translate(left, top); // 偏移画布
            float scale = getAllScale();
            canvas.scale(scale, scale); // 缩放画布

            Bitmap bitmap = null;
            if(mOptimizeDrawing) {
                bitmap =  mBitmap_c;
            } else if(mBitmap_f != null) {
                bitmap = mBitmap_f;
            } else {
                bitmap = mBitmap_b;
            }
            int saveCount = canvas.save(); // 1
            List<GraffitiPath> items = mItemStack;
            if (mOptimizeDrawing) {
                items = mItemStackOnViewCanvas;
            }
            LogUtils.i("m3: ForegroundView doDraw bitmap.getWidth:" + bitmap.getWidth() + ", bitmap.getHeight:" + bitmap.getHeight());
            if (!mIsDrawableOutside) { // 裁剪绘制区域为图片区域
                canvas.clipRect(0, 0, bitmap.getWidth(), bitmap.getHeight());
            }
            if(mBitmap_f != null) {
                canvas.drawBitmap(mBitmap_f, 0, 0, null);
            }
            for (GraffitiPath item : items) {
                item.draw(canvas);
            }
            canvas.restoreToCount(saveCount);
        }
    }

    //遮罩，只显示图片的一部分
    private class MaskView extends View {
        float mLeft;
        float mTop;
        float mRight;
        float mBottom;
        public MaskView(Context context) {
            super(context);

            // 关闭硬件加速，某些绘图操作不支持硬件加速
            //setLayerType(LAYER_TYPE_SOFTWARE, null); //有这句代码，会在rcyclerview中，超过一页的的涂鸦，中途无法绘制，只能在抬笔时绘制
        }


        @Override
        protected void onDraw(Canvas canvas) {
            LogUtils.i("m3: MaskView onDraw");
            canvas.setDrawFilter(new PaintFlagsDrawFilter(0, Paint.ANTI_ALIAS_FLAG | Paint.FILTER_BITMAP_FLAG));

            canvas.drawRect(new RectF(mLeft, mTop, mRight, mBottom), mMaskPaint);
        }

        public void setRect(float left, float top, float right, float bottom) {
            mLeft = left;
            mTop = top;
            mRight = right;
            mBottom = bottom;
            invalidate();
        }
    }
}
